From 78b20c695389df112985986f53738f80fdb813d3 Mon Sep 17 00:00:00 2001 From: "john.levon@sun.com" Date: Tue, 20 Feb 2007 14:54:04 -0800 Subject: [PATCH] Add iso9660 support to libfsimage. Signed-off-by: John Levon --- tools/libfsimage/Makefile | 2 +- tools/libfsimage/common/fsimage_grub.c | 78 ++++ tools/libfsimage/common/fsimage_grub.h | 5 +- tools/libfsimage/common/mapfile-GNU | 1 + tools/libfsimage/common/mapfile-SunOS | 1 + tools/libfsimage/ext2fs/fsys_ext2fs.c | 89 +---- tools/libfsimage/iso9660/Makefile | 15 + tools/libfsimage/iso9660/fsys_iso9660.c | 463 ++++++++++++++++++++++ tools/libfsimage/iso9660/iso9660.h | 219 ++++++++++ tools/libfsimage/reiserfs/fsys_reiserfs.c | 77 ---- 10 files changed, 783 insertions(+), 167 deletions(-) create mode 100644 tools/libfsimage/iso9660/Makefile create mode 100644 tools/libfsimage/iso9660/fsys_iso9660.c create mode 100644 tools/libfsimage/iso9660/iso9660.h diff --git a/tools/libfsimage/Makefile b/tools/libfsimage/Makefile index 394c7f4dfa..2631230cae 100644 --- a/tools/libfsimage/Makefile +++ b/tools/libfsimage/Makefile @@ -1,7 +1,7 @@ XEN_ROOT = ../.. include $(XEN_ROOT)/tools/Rules.mk -SUBDIRS-y = common ufs reiserfs +SUBDIRS-y = common ufs reiserfs iso9660 SUBDIRS-y += $(shell ./check-libext2fs) .PHONY: all diff --git a/tools/libfsimage/common/fsimage_grub.c b/tools/libfsimage/common/fsimage_grub.c index 27a1481eb7..0e12ce5530 100644 --- a/tools/libfsimage/common/fsimage_grub.c +++ b/tools/libfsimage/common/fsimage_grub.c @@ -122,6 +122,84 @@ fsig_disk_read_junk(void) return (&disk_read_junk); } +#if defined(__i386__) || defined(__x86_64__) + +#ifdef __amd64 +#define BSF "bsfq" +#else +#define BSF "bsfl" +#endif +unsigned long +fsig_log2 (unsigned long word) +{ + __asm__ (BSF " %1,%0" + : "=r" (word) + : "r" (word)); + return word; +} + +#elif defined(__ia64__) + +#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# define ia64_popcnt(x) __builtin_popcountl(x) +#else +# define ia64_popcnt(x) \ + ({ \ + __u64 ia64_intri_res; \ + asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \ + ia64_intri_res; \ + }) +#endif + +unsigned long +fsig_log2 (unsigned long word) +{ + unsigned long result; + + result = ia64_popcnt((word - 1) & ~word); + return result; +} + +#elif defined(__powerpc__) + +#ifdef __powerpc64__ +#define PPC_CNTLZL "cntlzd" +#else +#define PPC_CNTLZL "cntlzw" +#endif +#define BITS_PER_LONG (sizeof(long) * 8) + +static int +__ilog2(unsigned long x) +{ + int lz; + + asm (PPC_CNTLZL " %0,%1" : "=r" (lz) : "r" (x)); + return BITS_PER_LONG - 1 - lz; +} + +unsigned long +fsig_log2 (unsigned long word) +{ + return __ilog2(word & -word); +} + +#else /* Unoptimized */ + +unsigned long +fsig_log2 (unsigned long word) +{ + unsigned long result = 0; + + while (!(word & 1UL)) + { + result++; + word >>= 1; + } + return result; +} +#endif + int fsig_devread(fsi_file_t *ffi, unsigned int sector, unsigned int offset, unsigned int bufsize, char *buf) diff --git a/tools/libfsimage/common/fsimage_grub.h b/tools/libfsimage/common/fsimage_grub.h index 9fc8c467b2..800a918655 100644 --- a/tools/libfsimage/common/fsimage_grub.h +++ b/tools/libfsimage/common/fsimage_grub.h @@ -57,17 +57,20 @@ typedef struct fsig_plugin_ops { #define disk_read_func (*fsig_disk_read_junk()) #define disk_read_hook (*fsig_disk_read_junk()) #define print_possibilities 0 +#define noisy_printf #define grub_memset memset #define grub_memmove memmove +#define grub_log2 fsig_log2 extern char **fsig_disk_read_junk(void); +unsigned long fsig_log2(unsigned long); #define ERR_FSYS_CORRUPT 1 +#define ERR_OUTSIDE_PART 1 #define ERR_SYMLINK_LOOP 1 #define ERR_FILELENGTH 1 #define ERR_BAD_FILETYPE 1 -#define ERR_BAD_FILETYPE 1 #define ERR_FILE_NOT_FOUND 1 fsi_plugin_ops_t *fsig_init(fsi_plugin_t *, fsig_plugin_ops_t *); diff --git a/tools/libfsimage/common/mapfile-GNU b/tools/libfsimage/common/mapfile-GNU index 4bffdeafb0..ced9ade69c 100644 --- a/tools/libfsimage/common/mapfile-GNU +++ b/tools/libfsimage/common/mapfile-GNU @@ -20,6 +20,7 @@ VERSION { fsig_init; fsig_devread; fsig_substring; + fsig_log2; fsig_fs_buf; fsig_file_alloc; fsig_file_buf; diff --git a/tools/libfsimage/common/mapfile-SunOS b/tools/libfsimage/common/mapfile-SunOS index 63f17e1832..21ef67605a 100644 --- a/tools/libfsimage/common/mapfile-SunOS +++ b/tools/libfsimage/common/mapfile-SunOS @@ -19,6 +19,7 @@ libfsimage.so.1.0 { fsig_init; fsig_devread; fsig_substring; + fsig_log2; fsig_fs_buf; fsig_file_alloc; fsig_file_buf; diff --git a/tools/libfsimage/ext2fs/fsys_ext2fs.c b/tools/libfsimage/ext2fs/fsys_ext2fs.c index 4a8f595f43..7a25c55022 100644 --- a/tools/libfsimage/ext2fs/fsys_ext2fs.c +++ b/tools/libfsimage/ext2fs/fsys_ext2fs.c @@ -191,7 +191,7 @@ struct ext2_dir_entry /* ext2/super.c */ -#define log2(n) ffz(~(n)) +#define log2(n) grub_log2(n) #define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */ #define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */ @@ -232,93 +232,6 @@ struct ext2_dir_entry #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#if defined(__i386__) || defined(__x86_64__) -/* include/asm-i386/bitops.h */ -/* - * ffz = Find First Zero in word. Undefined if no zero exists, - * so code should check against ~0UL first.. - */ -#ifdef __amd64 -#define BSF "bsfq" -#else -#define BSF "bsfl" -#endif -static __inline__ unsigned long -ffz (unsigned long word) -{ - __asm__ (BSF " %1,%0" -: "=r" (word) -: "r" (~word)); - return word; -} - -#elif defined(__ia64__) - -typedef unsigned long __u64; - -#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# define ia64_popcnt(x) __builtin_popcountl(x) -#else -# define ia64_popcnt(x) \ - ({ \ - __u64 ia64_intri_res; \ - asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \ - ia64_intri_res; \ - }) -#endif - -static __inline__ unsigned long -ffz (unsigned long word) -{ - unsigned long result; - - result = ia64_popcnt(word & (~word - 1)); - return result; -} - -#elif defined(__powerpc__) - -#ifdef __powerpc64__ -#define PPC_CNTLZL "cntlzd" -#else -#define PPC_CNTLZL "cntlzw" -#endif -#define BITS_PER_LONG (sizeof(long) * 8) - -static __inline__ int -__ilog2(unsigned long x) -{ - int lz; - - asm (PPC_CNTLZL " %0,%1" : "=r" (lz) : "r" (x)); - return BITS_PER_LONG - 1 - lz; -} - -static __inline__ unsigned long -ffz (unsigned long word) -{ - if ((word = ~word) == 0) - return BITS_PER_LONG; - return __ilog2(word & -word); -} - -#else /* Unoptimized */ - -static __inline__ unsigned long -ffz (unsigned long word) -{ - unsigned long result; - - result = 0; - while(word & 1) - { - result++; - word >>= 1; - } - return result; -} -#endif - /* check filesystem types and read superblock into memory buffer */ int ext2fs_mount (fsi_file_t *ffi, const char *options) diff --git a/tools/libfsimage/iso9660/Makefile b/tools/libfsimage/iso9660/Makefile new file mode 100644 index 0000000000..6e7169490b --- /dev/null +++ b/tools/libfsimage/iso9660/Makefile @@ -0,0 +1,15 @@ +XEN_ROOT = ../../.. + +LIB_SRCS-y = fsys_iso9660.c + +FS = iso9660 + +.PHONY: all +all: fs-all + +.PHONY: install +install: fs-install + +fsys_iso9660.c: iso9660.h + +include $(XEN_ROOT)/tools/libfsimage/Rules.mk diff --git a/tools/libfsimage/iso9660/fsys_iso9660.c b/tools/libfsimage/iso9660/fsys_iso9660.c new file mode 100644 index 0000000000..a07b461ce7 --- /dev/null +++ b/tools/libfsimage/iso9660/fsys_iso9660.c @@ -0,0 +1,463 @@ +/* + * ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader) + * including Rock Ridge Extensions support + * + * Copyright (C) 1998, 1999 Kousuke Takai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * References: + * linux/fs/isofs/rock.[ch] + * mkisofs-1.11.1/diag/isoinfo.c + * mkisofs-1.11.1/iso9660.h + * (all are written by Eric Youngdale) + * + * Modifications by: + * Leonid Lisovskiy 2003 + */ + +#include +#include + +#include "iso9660.h" + +#define MAXINT INT_MAX + +/* iso9660 super-block data in memory */ +struct iso_sb_info { + unsigned long vol_sector; + +}; + +/* iso fs inode data in memory */ +struct iso_inode_info { + unsigned long file_start; +}; + +#define ISO_SUPER \ + ((struct iso_sb_info *)(FSYS_BUF)) +#define INODE \ + ((struct iso_inode_info *)(FSYS_BUF+sizeof(struct iso_sb_info))) +#define PRIMDESC ((struct iso_primary_descriptor *)(FSYS_BUF + 2048)) +#define DIRREC ((struct iso_directory_record *)(FSYS_BUF + 4096)) +#define RRCONT_BUF ((unsigned char *)(FSYS_BUF + 6144)) +#define NAME_BUF ((unsigned char *)(FSYS_BUF + 8192)) + + +#define log2 grub_log2 + +static int +iso9660_devread (fsi_file_t *ffi, int sector, int byte_offset, int byte_len, char *buf) +{ + static int read_count = 0, threshold = 2; + unsigned short sector_size_lg2 = log2(512 /*buf_geom.sector_size*/); + + /* + * We have to use own devread() function since BIOS return wrong geometry + */ + if (sector < 0) + { + errnum = ERR_OUTSIDE_PART; + return 0; + } + if (byte_len <= 0) + return 1; + +#if 0 + sector += (byte_offset >> sector_size_lg2); + byte_offset &= (buf_geom.sector_size - 1); + asm volatile ("shl%L0 %1,%0" + : "=r"(sector) + : "Ic"((int8_t)(ISO_SECTOR_BITS - sector_size_lg2)), + "0"(sector)); +#else + sector = (sector * 4) + (byte_offset >> sector_size_lg2); + byte_offset &= 511; +#endif + +#if !defined(STAGE1_5) + if (disk_read_hook && debug) + printf ("<%d, %d, %d>", sector, byte_offset, byte_len); +#endif /* !STAGE1_5 */ + + read_count += (byte_len >> 9); + if ((read_count >> 11) > threshold) { + noisy_printf("."); + threshold += 2; /* one dot every 2 MB */ + } + return devread(ffi, sector, byte_offset, byte_len, buf); +} + +int +iso9660_mount (fsi_file_t *ffi, const char *options) +{ + unsigned int sector; + + /* + * Because there is no defined slice type ID for ISO-9660 filesystem, + * this test will pass only either (1) if entire disk is used, or + * (2) if current partition is BSD style sub-partition whose ID is + * ISO-9660. + */ +#if 0 + if ((current_partition != 0xFFFFFF) + && !IS_PC_SLICE_TYPE_BSD_WITH_FS(current_slice, FS_ISO9660)) + return 0; +#endif + + /* + * Currently, only FIRST session of MultiSession disks are supported !!! + */ + for (sector = 16 ; sector < 32 ; sector++) + { + if (!iso9660_devread(ffi, sector, 0, sizeof(*PRIMDESC), (char *)PRIMDESC)) + break; + /* check ISO_VD_PRIMARY and ISO_STANDARD_ID */ + if (PRIMDESC->type.l == ISO_VD_PRIMARY + && !memcmp(PRIMDESC->id, ISO_STANDARD_ID, sizeof(PRIMDESC->id))) + { + ISO_SUPER->vol_sector = sector; + INODE->file_start = 0; +#if 0 + fsmax = PRIMDESC->volume_space_size.l; +#endif + return 1; + } + } + + return 0; +} + +int +iso9660_dir (fsi_file_t *ffi, char *dirname) +{ + struct iso_directory_record *idr; + RR_ptr_t rr_ptr; + struct rock_ridge *ce_ptr; + unsigned int pathlen; + int size; + unsigned int extent; + unsigned char file_type; + unsigned int rr_len; + unsigned char rr_flag; + + idr = &PRIMDESC->root_directory_record; + INODE->file_start = 0; + + do + { + while (*dirname == '/') /* skip leading slashes */ + dirname++; + /* pathlen = strcspn(dirname, "/\n\t "); */ + for (pathlen = 0 ; + dirname[pathlen] + && !isspace(dirname[pathlen]) && dirname[pathlen] != '/' ; + pathlen++) + ; + + size = idr->size.l; + extent = idr->extent.l; + + while (size > 0) + { + if (!iso9660_devread(ffi, extent, 0, ISO_SECTOR_SIZE, (char *)DIRREC)) + { + errnum = ERR_FSYS_CORRUPT; + return 0; + } + extent++; + + idr = (struct iso_directory_record *)DIRREC; + for (; idr->length.l > 0; + idr = (struct iso_directory_record *)((char *)idr + idr->length.l) ) + { + const char *name = idr->name; + unsigned int name_len = idr->name_len.l; + + file_type = (idr->flags.l & 2) ? ISO_DIRECTORY : ISO_REGULAR; + if (name_len == 1) + { + if ((name[0] == 0) || /* self */ + (name[0] == 1)) /* parent */ + continue; + } + if (name_len > 2 && CHECK2(name + name_len - 2, ';', '1')) + { + name_len -= 2; /* truncate trailing file version */ + if (name_len > 1 && name[name_len - 1] == '.') + name_len--; /* truncate trailing dot */ + } + + /* + * Parse Rock-Ridge extension + */ + rr_len = (idr->length.l - idr->name_len.l + - sizeof(struct iso_directory_record) + + sizeof(idr->name)); + rr_ptr.ptr = ((unsigned char *)idr + idr->name_len.l + + sizeof(struct iso_directory_record) + - sizeof(idr->name)); + if (rr_ptr.i & 1) + rr_ptr.i++, rr_len--; + ce_ptr = NULL; + rr_flag = RR_FLAG_NM | RR_FLAG_PX /*| RR_FLAG_SL*/; + + while (rr_len >= 4) + { + if (rr_ptr.rr->version != 1) + { +#ifndef STAGE1_5 + if (debug) + printf( + "Non-supported version (%d) RockRidge chunk " + "`%c%c'\n", rr_ptr.rr->version, + rr_ptr.rr->signature & 0xFF, + rr_ptr.rr->signature >> 8); +#endif + } + else + { + switch (rr_ptr.rr->signature) + { + case RRMAGIC('R', 'R'): + if ( rr_ptr.rr->len >= (4+sizeof(struct RR))) + rr_flag &= rr_ptr.rr->u.rr.flags.l; + break; + case RRMAGIC('N', 'M'): + name = rr_ptr.rr->u.nm.name; + name_len = rr_ptr.rr->len - (4+sizeof(struct NM)); + rr_flag &= ~RR_FLAG_NM; + break; + case RRMAGIC('P', 'X'): + if (rr_ptr.rr->len >= (4+sizeof(struct PX))) + { + file_type = ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT) + == POSIX_S_IFREG + ? ISO_REGULAR + : ((rr_ptr.rr->u.px.mode.l & POSIX_S_IFMT) + == POSIX_S_IFDIR + ? ISO_DIRECTORY : ISO_OTHER)); + rr_flag &= ~RR_FLAG_PX; + } + break; + case RRMAGIC('C', 'E'): + if (rr_ptr.rr->len >= (4+sizeof(struct CE))) + ce_ptr = rr_ptr.rr; + break; +#if 0 // RockRidge symlinks are not supported yet + case RRMAGIC('S', 'L'): + { + int slen; + unsigned char rootflag, prevflag; + char *rpnt = NAME_BUF+1024; + struct SL_component *slp; + + slen = rr_ptr.rr->len - (4+1); + slp = &rr_ptr.rr->u.sl.link; + while (slen > 1) + { + rootflag = 0; + switch (slp->flags.l) + { + case 0: + memcpy(rpnt, slp->text, slp->len); + rpnt += slp->len; + break; + case 4: + *rpnt++ = '.'; + /* fallthru */ + case 2: + *rpnt++ = '.'; + break; + case 8: + rootflag = 1; + *rpnt++ = '/'; + break; + default: + printf("Symlink component flag not implemented (%d)\n", + slp->flags.l); + slen = 0; + break; + } + slen -= slp->len + 2; + prevflag = slp->flags.l; + slp = (struct SL_component *) ((char *) slp + slp->len + 2); + + if (slen < 2) + { + /* + * If there is another SL record, and this component + * record isn't continued, then add a slash. + */ + if ((!rootflag) && (rr_ptr.rr->u.sl.flags.l & 1) && !(prevflag & 1)) + *rpnt++='/'; + break; + } + + /* + * If this component record isn't continued, then append a '/'. + */ + if (!rootflag && !(prevflag & 1)) + *rpnt++ = '/'; + } + *rpnt++ = '\0'; + grub_putstr(NAME_BUF+1024);// debug print! + } + rr_flag &= ~RR_FLAG_SL; + break; +#endif + default: + break; + } + } + if (!rr_flag) + /* + * There is no more extension we expects... + */ + break; + + rr_len -= rr_ptr.rr->len; + rr_ptr.ptr += rr_ptr.rr->len; + if (rr_len < 4 && ce_ptr != NULL) + { + /* preserve name before loading new extent. */ + if( RRCONT_BUF <= (unsigned char *)name + && (unsigned char *)name < RRCONT_BUF + ISO_SECTOR_SIZE ) + { + memcpy(NAME_BUF, name, name_len); + name = NAME_BUF; + } + rr_ptr.ptr = RRCONT_BUF + ce_ptr->u.ce.offset.l; + rr_len = ce_ptr->u.ce.size.l; + if (!iso9660_devread(ffi, ce_ptr->u.ce.extent.l, 0, ISO_SECTOR_SIZE, RRCONT_BUF)) + { + errnum = 0; /* this is not fatal. */ + break; + } + ce_ptr = NULL; + } + } /* rr_len >= 4 */ + + filemax = MAXINT; + if (name_len >= pathlen + && !memcmp(name, dirname, pathlen)) + { + if (dirname[pathlen] == '/' || !print_possibilities) + { + /* + * DIRNAME is directory component of pathname, + * or we are to open a file. + */ + if (pathlen == name_len) + { + if (dirname[pathlen] == '/') + { + if (file_type != ISO_DIRECTORY) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + goto next_dir_level; + } + if (file_type != ISO_REGULAR) + { + errnum = ERR_BAD_FILETYPE; + return 0; + } + INODE->file_start = idr->extent.l; + filepos = 0; + filemax = idr->size.l; + return 1; + } + } + else /* Completion */ + { +#ifndef STAGE1_5 + if (print_possibilities > 0) + print_possibilities = -print_possibilities; + memcpy(NAME_BUF, name, name_len); + NAME_BUF[name_len] = '\0'; + print_a_completion (NAME_BUF); +#endif + } + } + } /* for */ + + size -= ISO_SECTOR_SIZE; + } /* size>0 */ + + if (dirname[pathlen] == '/' || print_possibilities >= 0) + { + errnum = ERR_FILE_NOT_FOUND; + return 0; + } + + next_dir_level: + dirname += pathlen; + + } while (*dirname == '/'); + + return 1; +} + +int +iso9660_read (fsi_file_t *ffi, char *buf, int len) +{ + int sector, blkoffset, size, ret; + + if (INODE->file_start == 0) + return 0; + + ret = 0; + blkoffset = filepos & (ISO_SECTOR_SIZE - 1); + sector = filepos >> ISO_SECTOR_BITS; + while (len > 0) + { + size = ISO_SECTOR_SIZE - blkoffset; + if (size > len) + size = len; + + disk_read_func = disk_read_hook; + + if (!iso9660_devread(ffi, INODE->file_start + sector, blkoffset, size, buf)) + return 0; + + disk_read_func = NULL; + + len -= size; + buf += size; + ret += size; + filepos += size; + sector++; + blkoffset = 0; + } + + return ret; +} + +fsi_plugin_ops_t * +fsi_init_plugin(int version, fsi_plugin_t *fp, const char **name) +{ + static fsig_plugin_ops_t ops = { + FSIMAGE_PLUGIN_VERSION, + .fpo_mount = iso9660_mount, + .fpo_dir = iso9660_dir, + .fpo_read = iso9660_read + }; + + *name = "iso9660"; + return (fsig_init(fp, &ops)); +} diff --git a/tools/libfsimage/iso9660/iso9660.h b/tools/libfsimage/iso9660/iso9660.h new file mode 100644 index 0000000000..83d0019775 --- /dev/null +++ b/tools/libfsimage/iso9660/iso9660.h @@ -0,0 +1,219 @@ +/* + * ISO 9660 filesystem backend for GRUB (GRand Unified Bootloader) + * including Rock Ridge Extensions support + * + * Copyright (C) 1998, 1999 Kousuke Takai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +/* + * References: + * linux/fs/isofs/rock.[ch] + * mkisofs-1.11.1/diag/isoinfo.c + * mkisofs-1.11.1/iso9660.h + * (all are written by Eric Youngdale) + */ + +#ifndef _ISO9660_H_ +#define _ISO9660_H_ + +#define ISO_SECTOR_BITS (11) +#define ISO_SECTOR_SIZE (1<= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) -# define ia64_popcnt(x) __builtin_popcountl(x) -#else -# define ia64_popcnt(x) \ - ({ \ - __u64 ia64_intri_res; \ - asm ("popcnt %0=%1" : "=r" (ia64_intri_res) : "r" (x)); \ - ia64_intri_res; \ - }) -#endif - -static __inline__ unsigned long -grub_log2 (unsigned long word) -{ - unsigned long result; - - result = ia64_popcnt((word - 1) & ~word); - return result; -} - -#elif defined(__powerpc__) - -#ifdef __powerpc64__ -#define PPC_CNTLZL "cntlzd" -#else -#define PPC_CNTLZL "cntlzw" -#endif -#define BITS_PER_LONG (sizeof(long) * 8) - -static __inline__ int -__ilog2(unsigned long x) -{ - int lz; - - asm (PPC_CNTLZL " %0,%1" : "=r" (lz) : "r" (x)); - return BITS_PER_LONG - 1 - lz; -} - -static __inline__ unsigned long -grub_log2 (unsigned long word) -{ - return __ilog2(word & -word); -} - -#else /* Unoptimized */ - -static __inline__ unsigned long -grub_log2 (unsigned long word) -{ - unsigned long result = 0; - - while (!(word & 1UL)) - { - result++; - word >>= 1; - } - return result; -} -#endif #define log2 grub_log2 static __inline__ int -- 2.30.2